//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Eas.WebCrawler.Model.Core;
using Eas.WebCrawler.Interfaces;
using NMock2;

namespace Eas.WebCrawler.Test.Model {
    /// <summary>
    /// Summary description for ActionTransitionTests
    /// </summary>
    [TestClass]
    public class ActionTransitionTests {
        public ActionTransitionTests() {
            //
            // TODO: Add constructor logic here
            //
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        Mockery _Mockery = null;
        WorkerContext _Context = null;
        Eas.WebCrawler.Model.Gateway.WebGateway _Gateway = null;
        BaseProcessingState _State = null;
        Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents _Events = null;
        bool _WasStarted = false;
        bool _WasPaused = false;
        bool _WasUnPaused = false;
        bool _WasStopped = false;
        Uri _ProcessedUri = null;
        string _ProcessedUriText = null;

        [TestInitialize()]
        public void MyTestInitialize() {
            _ProcessedUriText = null;
            _ProcessedUri = null;
            _WasStarted = false;
            _WasPaused = false;
            _WasUnPaused = false;
            _WasStopped = false;
            _Mockery = new Mockery();
            _Gateway = _Mockery.NewMock<Eas.WebCrawler.Model.Gateway.WebGateway>();
            TestSettings settings = new TestSettings();
            settings.SleepTimeInMilliseconds = 10;
            _Context = Eas.WebCrawler.Model.WebCrawlerFactory.CreateWorkerContext(settings, _Gateway, new Eas.WebCrawler.Model.Actions.BaseActionFactory());
            _State = _Context.StateTracker[0];
            _Events = (Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents)_Context.Events;
            _Events.Stopped += new EventHandler(_Events_AfterStop);
            _Events.Paused += new EventHandler(_Events_AfterPause);
            _Events.Starting += new EventHandler(_Events_BeforeStart);
            _Events.Unpausing += new EventHandler(_Events_BeforeUnPause);
            _Events.OnTrace += new EventHandler<ProcessingStateMessageEventArgs>(_Events_OnTrace);
            _Events.OnError += new EventHandler<ProcessingStateMessageEventArgs>(_Events_OnError);
        }

        void _Events_OnError(object sender, ProcessingStateMessageEventArgs e) {
            System.Diagnostics.Trace.WriteLine(e.Message);
        }

        void _Events_OnTrace(object sender, ProcessingStateMessageEventArgs e) {
            System.Diagnostics.Trace.WriteLine(e.Message);
        }

        void _Events_BeforeUnPause(object sender, EventArgs e) {
            _WasUnPaused = true;
        }

        void _Events_BeforeStart(object sender, EventArgs e) {
            _WasStarted = true;
        }

        void _Events_AfterPause(object sender, EventArgs e) {
            _WasPaused = true;
        }

        void _Events_AfterStop(object sender, EventArgs e) {
            _WasStopped = true;
        }

        //
        // Use TestCleanup to run code after each test has run
        [TestCleanup()]
        public void MyTestCleanup() {
            if (_WasPaused && _State.PausedAction != null) {
                _State.PausedAction.EndAction(_Context, _State, _State.PausedResult);
            }
            _Events.Fire_Stopped();
            _ProcessedUriText = null;
            _ProcessedUri = null;
            _Context.StateTracker.ValidateNoResultsAreOpened();
            _State = null;
            _Events = null;
            _Context.Dispose();
            _Mockery.VerifyAllExpectationsHaveBeenMet();
            _Mockery.Dispose();
            _WasStarted = false;
            _WasPaused = false;
            _WasUnPaused = false;
            _WasStopped = false;
            GC.Collect();
        }

        //
        #endregion

        private void DoUnstartedToUnstarted(BaseProcessingState state, WorkerContext context) {
            Assert.AreEqual<WorkerState>(WorkerState.Unstarted, state.WorkerState);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.UnstartedAction), state);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.UnstartedAction), state);
        }

        private void DoUnstartedToStopped(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToUnstarted(state, context);
            _Events.Fire_Starting();
            context.StateTracker.RequestChange(WorkerState.Stopped);
            StepForward(state, context);
            VerifyStopped(state, context);
        }

        private void DoUnstartedToPaused(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToUnstarted(state, context);
            context.StateTracker.RequestChange(WorkerState.Paused);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PauseAction), state);
            Assert.IsInstanceOfType(state.PausedAction, typeof(Eas.WebCrawler.Model.Actions.UnstartedAction));
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(state.WasPaused);
            Assert.IsNotNull(state.PausedResult);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PauseAction), state);
            Assert.IsInstanceOfType(state.PausedAction, typeof(Eas.WebCrawler.Model.Actions.UnstartedAction));
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(state.WasPaused);
            Assert.IsNotNull(state.PausedResult);
        }

        private void DoUnstartedToPausedToUnstarted(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToPaused(state, context);
            _Events.Fire_UnPausing();
            context.StateTracker.RequestChange(WorkerState.Working);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.UnstartedAction), state);
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(_WasUnPaused);
            Assert.IsTrue(state.WasPaused);
            Assert.IsNull(state.PausedResult);
            Assert.IsNull(state.PausedAction);
        }

        private void DoUnstartedToPausedToStopped(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToPaused(state, context);
            context.StateTracker.RequestChange(WorkerState.Stopped);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.TerminalAction), state);
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(_WasStopped);
            Assert.IsTrue(state.WasPaused);
            Assert.IsNull(state.PausedResult);
            Assert.IsNull(state.PausedAction);
        }

        private void DoUnstartedToGetRequest(BaseProcessingState state, WorkerContext context, Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents events) {
            DoUnstartedToUnstarted(state, context);
            events.Fire_Starting();
            context.StateTracker.RequestChange(WorkerState.Working);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state);
            Assert.IsTrue(_WasStarted);
        }

        private void DoUnstartedToGetRequestToGetResponse(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToGetRequest(state, context, _Events);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetResponseAction), state);
            Assert.AreEqual<Uri>(UriHelper.Google, state.Request.Uri);
        }
        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToUnstarted test.</summary>
        public void TestFromUnstartedToUnstarted() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToUnstarted(state, context);

        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToStopped test.</summary>
        public void TestFromUnstartedToStopped() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToStopped(state, context);

        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToPaused test.</summary>
        public void TestFromUnstartedToPaused() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToPaused(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToPausedToUnstarted test.</summary>
        public void TestFromUnstartedToPausedToUnstarted() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToPausedToUnstarted(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToPausedToStopped test.</summary>
        public void TestFromUnstartedToPausedToStopped() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToPausedToStopped(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToGetRequest test.</summary>
        public void TestFromUnstartedToGetRequest() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;

            DoUnstartedToGetRequest(state, context, _Events);
        }

        [TestMethod]
        /// <summary>Executes the TestFromGetRequestToGetResponse test.</summary>
        public void TestFromUnstartedToGetRequestToGetResponse() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToGetResponse(state, context);
        }


        [TestMethod]
        /// <summary>Executes the TestFromGetRequestToTerminalBecauseOfNoMoreRequests test.</summary>
        public void TestFromGetRequestToTerminalBecauseOfNoMoreRequests() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequest(state, context, _Events);
            context.WebCrawlerContext.Store.PopRequest();
            context.WebCrawlerContext.Store.PopRequest();
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PendingGetRequestAction), state);
            StepForward(state, context);
            VerifyStopped(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestFromGetRequestToTerminalBecauseOfNoMoreRequestsTwo test.</summary>
        public void TestFromGetRequestToTerminalBecauseOfNoMoreRequestsTwo() {
            TestSettings settings = new TestSettings();
            settings.SleepTimeInMilliseconds = 10;
            settings.WorkerCount = 2;
            using (WorkerContext context = Eas.WebCrawler.Model.WebCrawlerFactory.CreateWorkerContext(settings, _Gateway, new Eas.WebCrawler.Model.Actions.BaseActionFactory())) {
                BaseProcessingState state0 = context.StateTracker[0];
                BaseProcessingState state1 = context.StateTracker[1];
                _Events = (Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents)context.Events;
                _Events.Stopped += new EventHandler(_Events_AfterStop);
                _Events.Paused += new EventHandler(_Events_AfterPause);
                _Events.Starting += new EventHandler(_Events_BeforeStart);
                _Events.Unpausing += new EventHandler(_Events_BeforeUnPause);
                _Events.OnTrace += new EventHandler<ProcessingStateMessageEventArgs>(_Events_OnTrace);
                _Events.OnError += new EventHandler<ProcessingStateMessageEventArgs>(_Events_OnError);
                _Events.Fire_Starting();
                Assert.AreEqual<int>(2, context.WebCrawlerContext.Store.Count);

                DoUnstartedToUnstarted(state0, context);
                context.StateTracker.RequestChange(WorkerState.Working);

                StepForward(state0, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state0);
                Assert.IsTrue(_WasStarted);

                StepForward(state1, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state1);

                context.WebCrawlerContext.Store.PopRequest();
                context.WebCrawlerContext.Store.PopRequest();
                Assert.AreEqual<int>(0, context.WebCrawlerContext.Store.Count);

                StepForward(state1, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PendingGetRequestAction), state1);

                StepForward(state1, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PendingGetRequestAction), state1);

                StepForward(state0, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PendingGetRequestAction), state0);

                StepForward(state1, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.TerminalAction), state1);

                StepForward(state0, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.TerminalAction), state0);

                VerifyStopped(state0, context);
                VerifyStopped(state1, context);
            }
        }


        [TestMethod]
        /// <summary>Executes the TestFromGetRequestToGetRequestBecauseOfNoMoreRequestsWithPendingWorkers test.</summary>
        public void TestFromGetRequestToGetRequestBecauseOfNoMoreRequestsWithPendingWorkers() {
            TestSettings settings = new TestSettings();
            settings.SleepTimeInMilliseconds = 10;
            settings.WorkerCount = 2;
            using (WorkerContext context = Eas.WebCrawler.Model.WebCrawlerFactory.CreateWorkerContext(settings, _Gateway, new Eas.WebCrawler.Model.Actions.BaseActionFactory())) {
                BaseProcessingState state0 = context.StateTracker[0];
                BaseProcessingState state1 = context.StateTracker[1];
                _Events = (Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents)context.Events;
                _Events.Stopped += new EventHandler(_Events_AfterStop);
                _Events.Paused += new EventHandler(_Events_AfterPause);
                _Events.Starting += new EventHandler(_Events_BeforeStart);
                _Events.Unpausing += new EventHandler(_Events_BeforeUnPause);
                _Events.Fire_Starting();
                Assert.AreEqual<int>(2, context.WebCrawlerContext.Store.Count);

                DoUnstartedToUnstarted(state0, context);
                context.StateTracker.RequestChange(WorkerState.Working);
                StepForward(state0, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state0);
                Assert.IsTrue(_WasStarted);

                StepForward(state0, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetResponseAction), state0);
                Assert.AreEqual<Uri>(UriHelper.Google, state0.Request.Uri);

                StepForward(state1, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state1);
                context.WebCrawlerContext.Store.PopRequest();
                Assert.AreEqual<int>(0, context.WebCrawlerContext.Store.Count);
                StepForward(state1, context);
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state1);
                Assert.IsFalse(_WasStopped);
            }
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToGetRequestToPaused test.</summary>
        public void TestFromUnstartedToGetRequestToPaused() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToPaused(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToGetRequestToPausedToGetResponse test.</summary>
        public void TestFromUnstartedToGetRequestToPausedToGetResponse() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToPausedToGetResponse(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToGetRequestToPausedToStopped test.</summary>
        public void TestUnstartedToGetRequestToPausedToStopped() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToPausedToStopped(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToReadStream test.</summary>
        public void TestFromUnstartedToReadStream() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            bool isTextResponse = true;
            DoUnstartedToReadStream(state, context, isTextResponse);
        }

        [TestMethod]
        /// <summary>Executes the TestFromUnstartedToReadStreamNotText test.</summary>
        public void TestFromUnstartedToReadStreamNotText() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            bool isTextResponse = false;
            DoUnstartedToReadStream(state, context, isTextResponse);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToReadStreamWithRedirect test.</summary>
        public void TestUnstartedToReadStreamWithRedirect() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToGetResponse(state, context);
            DoWebRequest(state, context, true, true, UriHelper.Yahoo);
            DoWebRequest(state, context, false, true, UriHelper.Msn);
            DoWebRequest(state, context, true, true, UriHelper.Microsoft);
            DoWebRequest(state, context, true, false, null);
        }

        [TestMethod]
        [ExpectedException(typeof(Eas.WebCrawler.Model.Core.WebFailureException))]
        /// <summary>Executes the TestTtoManyRedirects test, in which the <seealso cref="Eas.WebCrawler.Model.Core.WebFailureException"/> exception should be thrown during a succesfull test run.</summary>
        public void TestTtoManyRedirects() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToGetResponse(state, context);
            DoWebRequest(state, context, true, true, UriHelper.Yahoo);
            DoWebRequest(state, context, false, true, UriHelper.Msn);
            DoWebRequest(state, context, true, true, UriHelper.Microsoft);
            DoWebRequest(state, context, true, true, UriHelper.PhpRef);
            DoWebRequest(state, context, true, true, UriHelper.Yahoo);
            DoWebRequest(state, context, false, true, UriHelper.Msn);
            DoWebRequest(state, context, true, true, UriHelper.Microsoft);
            DoWebRequest(state, context, true, true, UriHelper.PhpRef);
            DoWebRequest(state, context, true, true, UriHelper.Yahoo);
            DoWebRequest(state, context, false, true, UriHelper.Msn);
            DoWebRequest(state, context, false, true, UriHelper.Yahoo);
            DoWebRequest(state, context, true, true, UriHelper.Microsoft, true, false);
        }

        [TestMethod]
        /// <summary>Executes the TestThrowOnCloseOfRedirect test</summary>
        public void TestThrowOnCloseOfRedirect() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToGetResponse(state, context);
            DoWebRequest(state, context, true, true, UriHelper.Yahoo, false, true);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToGetResponseToStopped test.</summary>
        public void TestUnstartedToGetResponseToStopped() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToGetResponse(state, context);
            context.StateTracker.RequestChange(WorkerState.Stopped);
            Eas.WebCrawler.Interfaces.WebRequestInterface webRequest = _Mockery.NewMock<Eas.WebCrawler.Interfaces.WebRequestInterface>();
            IAsyncResult getResponseResult = _Mockery.NewMock<IAsyncResult>();
            Eas.WebCrawler.Interfaces.WebResponseInterface webResponse = _Mockery.NewMock<WebResponseInterface>();

            NMock2.Expect.Once.On(_Gateway).Method("CreateWebRequest").WithAnyArguments().Will(NMock2.Return.Value(webRequest));
            NMock2.Expect.Once.On(_Gateway).Method("BeginGetResponse").WithAnyArguments().Will(NMock2.Return.Value(getResponseResult));
            NMock2.Expect.Once.On(_Gateway).Method("EndGetResponse").WithAnyArguments().Will(NMock2.Return.Value(webResponse));

            StepForward(state, context);
            VerifyStopped(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToGetResponseToStoppedWithFailedEndGetResponse test.</summary>
        public void TestUnstartedToGetResponseToStoppedWithFailedEndGetResponse() {
            BaseProcessingState state = _State;
            WorkerContext context = _Context;
            DoUnstartedToGetRequestToGetResponse(state, context);
            context.StateTracker.RequestChange(WorkerState.Stopped);
            Eas.WebCrawler.Interfaces.WebRequestInterface webRequest = _Mockery.NewMock<Eas.WebCrawler.Interfaces.WebRequestInterface>();
            IAsyncResult getResponseResult = _Mockery.NewMock<IAsyncResult>();
            Eas.WebCrawler.Interfaces.WebResponseInterface webResponse = _Mockery.NewMock<WebResponseInterface>();

            NMock2.Expect.Once.On(_Gateway).Method("CreateWebRequest").WithAnyArguments().Will(NMock2.Return.Value(webRequest));
            NMock2.Expect.Once.On(_Gateway).Method("BeginGetResponse").WithAnyArguments().Will(NMock2.Return.Value(getResponseResult));
            NMock2.Expect.Once.On(_Gateway).Method("EndGetResponse").WithAnyArguments().Will(NMock2.Throw.Exception(new WebFailureException("ss", 23, null)));

            StepForward(state, context);
            VerifyStopped(state, context);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToReadStreamToTerminal test.</summary>
        public void TestUnstartedToReadStreamToTerminal() {
            bool isTextResponse = true;
            DoReadStream(isTextResponse);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToReadStreanTOTerminalBinary test.</summary>
        public void TestUnstartedToReadStreanTOTerminalBinary() {
            bool isTextResponse = false;
            DoReadStream(isTextResponse);
        }

        [TestMethod]
        /// <summary>Executes the TestUnstartedToReadStreamToTerminalByStopping test.</summary>
        public void TestUnstartedToReadStreamToTerminalByStopping() {
            bool isTextResponse = false;
            string responseText = "hello 'http://www.msn.com' world. <a href='mailto://erik@saltwell.com'>erik</a> <a href='http://www.msn.com'>msdn</a> <a href='http://saltwell.com/erik.html'>c</a>.";
            TestSettings settings = new TestSettings();
            settings.Selector = new Eas.WebCrawler.PlugIns.Selectors.NameSelector(new Eas.WebCrawler.PlugIns.Selectors.ConstantSelector(false), new Eas.WebCrawler.PlugIns.Selectors.ConstantSelector(true), "saltwell.com");
            settings.SleepTimeInMilliseconds = 1;
            Eas.WebCrawler.Interfaces.CompletedRequestHistory history = _Mockery.NewMock<Eas.WebCrawler.Interfaces.CompletedRequestHistory>();
            using (WorkerContext context = Eas.WebCrawler.Model.WebCrawlerFactory.CreateWorkerContext(settings, new Eas.WebCrawler.Model.Gateway.BaseWebGateway(), new Eas.WebCrawler.Model.Actions.BaseActionFactory())) {
                BaseProcessingState state = _Context.StateTracker[0];
                state.Request = RequestHelper.rMicrosoft;
                state.IsTextResponse = isTextResponse;
                state.SetAction(context.ActionFactory.CreateStreamReadAction(state, context));
                _Events = (Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents)context.Events;
                _Events.Stopped += new EventHandler(_Events_AfterStop);
                _Events.Paused += new EventHandler(_Events_AfterPause);
                _Events.Starting += new EventHandler(_Events_BeforeStart);
                _Events.Unpausing += new EventHandler(_Events_BeforeUnPause);
                _Events.UrlProcessed += new EventHandler<UrlCompletedEventArgs>(_Events_UrlProcessed);
                _Events.Fire_Starting();
                context.WebCrawlerContext.Store.PopRequest();
                System.IO.Stream memoryStream = new System.IO.MemoryStream(System.Text.Encoding.ASCII.GetBytes(responseText));
                state.ResponseStream = memoryStream;

                context.StateTracker.RequestChange(WorkerState.Stopped);
                StepForward(state, context);

                VerifyStopped(state, context);
                context.StateTracker.ValidateNoResultsAreOpened();

            }

        }

        private void DoReadStream(bool isTextResponse) {
            string responseText = "hello 'http://www.msn.com' world.[{\"image_path\":\"\\/images\\/overview\\/thumbs\\/thumb_format.gif\". <a href='mailto://erik@saltwell.com'>erik</a> <a href='http://www.msn.com'>msdn</a> <a href='http://saltwell.com/erik.html'>c</a>.";
            DoReadStream(isTextResponse, responseText);

        }

        private void DoReadStream(bool isTextResponse, string responseText) {
            TestSettings settings = new TestSettings();
            settings.Selector = new Eas.WebCrawler.PlugIns.Selectors.NameSelector(new Eas.WebCrawler.PlugIns.Selectors.ConstantSelector(false), new Eas.WebCrawler.PlugIns.Selectors.ConstantSelector(true), "saltwell.com");
            settings.SleepTimeInMilliseconds = 1;
            Eas.WebCrawler.Interfaces.CompletedRequestHistory history = _Mockery.NewMock<Eas.WebCrawler.Interfaces.CompletedRequestHistory>();
            settings.CompletedRequestHistory.Dispose();
            settings.CompletedRequestHistory = history;
            NMock2.Expect.Once.On(history).Method("Initialize").WithAnyArguments();
            NMock2.Expect.Once.On(history).Method("GetCompletedRequests").WithAnyArguments().Will(NMock2.Return.Value(new Uri[] { }));
            using (WorkerContext context = Eas.WebCrawler.Model.WebCrawlerFactory.CreateWorkerContext(settings, new Eas.WebCrawler.Model.Gateway.BaseWebGateway(), new Eas.WebCrawler.Model.Actions.BaseActionFactory())) {
                BaseProcessingState state = _Context.StateTracker[0];
                state.Request = RequestHelper.rMicrosoft;
                state.IsTextResponse = isTextResponse;
                state.SetAction(context.ActionFactory.CreateStreamReadAction(state, context));
                _Events = (Eas.WebCrawler.Model.Events.BaseWebCrawlerEvents)context.Events;
                _Events.Stopped += new EventHandler(_Events_AfterStop);
                _Events.Paused += new EventHandler(_Events_AfterPause);
                _Events.Starting += new EventHandler(_Events_BeforeStart);
                _Events.Unpausing += new EventHandler(_Events_BeforeUnPause);
                _Events.UrlProcessed += new EventHandler<UrlCompletedEventArgs>(_Events_UrlProcessed);
                _Events.Fire_Starting();
                context.WebCrawlerContext.Store.PopRequest();
                System.IO.Stream memoryStream = new System.IO.MemoryStream(System.Text.Encoding.ASCII.GetBytes(responseText));
                state.ResponseStream = memoryStream;

                NMock2.Expect.Once.On(history).Method("AddCompletedRequest").With(UriHelper.Microsoft);
                NMock2.Expect.Once.On(history).Method("Dispose");

                StepForward(state, context);
                if (state.Action.GetType() == typeof(Eas.WebCrawler.Model.Actions.ReadStreamAction))
                    StepForward(state, context);

                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetRequestAction), state);
                Assert.AreEqual<Uri>(UriHelper.Microsoft, _ProcessedUri);


                if (isTextResponse) {
                    Assert.AreEqual<string>(responseText, _ProcessedUriText);
                    Assert.AreEqual<int>(2, context.WebCrawlerContext.Store.Count);
                }
                else
                    Assert.AreEqual<int>(1, context.WebCrawlerContext.Store.Count);//not a text response, so no links added.
                context.StateTracker.ValidateNoResultsAreOpened();
            }
        }

        void _Events_UrlProcessed(object sender, UrlCompletedEventArgs e) {
            _ProcessedUri = e.State.Request.Uri;
            if (e.State.IsTextResponse) {
                using (System.IO.TextReader reader = e.Storage.GetTextReader()) {
                    _ProcessedUriText = reader.ReadToEnd();
                }
            }
        }

        class EndReadAction : NMock2.IAction {
            /// <summary>The Stream calling read.</summary>
            /// <remarks>Backing field for the Stream property.</remarks>
            /// <seealso cref="Stream"/>
            private System.IO.Stream _Stream;

            /// <summary>The Stream calling read.</summary>
            public System.IO.Stream Stream {
                get { return _Stream; }
                set { _Stream = value; }
            }

            public EndReadAction(System.IO.Stream stream) {
                _Stream = stream;
            }

            #region IInvokable Members

            public void Invoke(NMock2.Monitoring.Invocation invocation) {
                invocation.Result = _Stream.EndRead((IAsyncResult)invocation.Parameters[1]);
            }

            #endregion

            #region ISelfDescribing Members

            public void DescribeTo(System.IO.TextWriter writer) {
                writer.Write(" EndReadAction ");
            }

            #endregion
        }

        private void DoUnstartedToReadStream(BaseProcessingState state, WorkerContext context, bool isTextResponse) {
            DoUnstartedToGetRequestToGetResponse(state, context);
            DoWebRequest(state, context, isTextResponse, false, null);
        }

        private void DoWebRequest(BaseProcessingState state, WorkerContext context, bool isTextResponse, bool isRedirect, Uri redirectUri) {
            DoWebRequest(state, context, isTextResponse, isRedirect, redirectUri, false, false);
        }

        private void DoWebRequest(BaseProcessingState state, WorkerContext context, bool isTextResponse, bool isRedirect, Uri redirectUri, bool error, bool throwOnClose) {
            Request nextRequest = null;
            Eas.WebCrawler.Interfaces.WebRequestInterface webRequest = _Mockery.NewMock<Eas.WebCrawler.Interfaces.WebRequestInterface>();
            IAsyncResult getResponseResult = _Mockery.NewMock<IAsyncResult>();
            Eas.WebCrawler.Interfaces.WebResponseInterface webResponse = _Mockery.NewMock<WebResponseInterface>();
            System.IO.Stream memoryStream = new System.IO.MemoryStream();
            NMock2.Expect.Once.On(_Gateway).Method("CreateWebRequest").WithAnyArguments().Will(NMock2.Return.Value(webRequest));
            NMock2.Expect.Once.On(_Gateway).Method("BeginGetResponse").WithAnyArguments().Will(NMock2.Return.Value(getResponseResult));
            NMock2.Expect.Once.On(_Gateway).Method("EndGetResponse").WithAnyArguments().Will(NMock2.Return.Value(webResponse));
            NMock2.Expect.Once.On(_Gateway).Method("IsRedirect").WithAnyArguments().Will(NMock2.Return.Value(isRedirect));
            if (!isRedirect) {
                if (!error) {
                    NMock2.Expect.Once.On(_Gateway).Method("GetResponseStream").WithAnyArguments().Will(NMock2.Return.Value(memoryStream));
                    NMock2.Expect.Once.On(_Gateway).Method("ResponseIsText").WithAnyArguments().Will(NMock2.Return.Value(isTextResponse));
                }
            }
            else {
                nextRequest = new Request(redirectUri, state.Request);
                if (!error) {
                    NMock2.Expect.Once.On(_Gateway).Method("GetRedirectUri").WithAnyArguments().Will(NMock2.Return.Value(redirectUri));
                    if (!throwOnClose) {
                        NMock2.Expect.Once.On(webRequest).Method("Abort").WithAnyArguments();
                        NMock2.Expect.Once.On(webResponse).Method("Close").WithAnyArguments();
                    }
                }

            }

            StepForward(state, context);


            if (!isRedirect) {
                Assert.AreSame(webRequest, state.WebRequest);
                Assert.AreSame(webResponse, state.WebResponse);
                Assert.AreEqual<bool>(isTextResponse, state.IsTextResponse);
                Assert.AreSame(memoryStream, state.ResponseStream);
            }
            else {
                Assert.IsNull(state.WebRequest);
                Assert.IsNull(state.WebResponse);
                Assert.IsNull(state.ResponseStream);
                Assert.AreEqual<Uri>(redirectUri, state.Request.Uri);
            }
            if (isRedirect)
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetResponseAction), state);
            else
                VerifyAction(typeof(Eas.WebCrawler.Model.Actions.ReadStreamAction), state);
        }

        private void DoUnstartedToGetRequestToPausedToStopped(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToGetRequestToPaused(state, context);
            context.StateTracker.RequestChange(WorkerState.Stopped);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.TerminalAction), state);
            Assert.IsNull(state.PausedAction);
            Assert.IsNull(state.PausedResult);
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(_WasStopped);
        }

        private void DoUnstartedToGetRequestToPausedToGetResponse(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToGetRequestToPaused(state, context);
            context.StateTracker.RequestChange(WorkerState.Working);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.GetResponseAction), state);
            Assert.IsNull(state.PausedAction);
            Assert.IsNull(state.PausedResult);
            Assert.IsTrue(_WasPaused);
            Assert.IsFalse(_WasStopped);
            Assert.AreEqual<Request>(RequestHelper.rGoogle, state.Request);
        }

        private void DoUnstartedToGetRequestToPaused(BaseProcessingState state, WorkerContext context) {
            DoUnstartedToGetRequest(state, context, _Events);
            context.StateTracker.RequestChange(WorkerState.Paused);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PauseAction), state);
            Assert.IsInstanceOfType(state.PausedAction, typeof(Eas.WebCrawler.Model.Actions.GetRequestAction));
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(state.WasPaused);
            Assert.IsNotNull(state.PausedResult);
            StepForward(state, context);
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.PauseAction), state);
            Assert.IsInstanceOfType(state.PausedAction, typeof(Eas.WebCrawler.Model.Actions.GetRequestAction));
            Assert.IsTrue(_WasPaused);
            Assert.IsTrue(state.WasPaused);
            Assert.IsNotNull(state.PausedResult);
        }


        private void VerifyStopped(BaseProcessingState state, WorkerContext context) {
            VerifyAction(typeof(Eas.WebCrawler.Model.Actions.TerminalAction), state);
            Assert.IsNull(state.Action.BeginAction(context, state, null));
            //Assert.IsTrue(state.WasTerminated);
            Assert.IsTrue(_WasStopped);
        }

        private void VerifyAction(Type type, BaseProcessingState state) {
            Assert.IsInstanceOfType(state.Action, type);
        }

        private void StepForward(BaseProcessingState state, WorkerContext context) {
            context.StateTracker.LoadChangeRequestsIntoState(state);
            IAsyncResult result = state.Action.BeginAction(context, state, null);
            BaseProcessingState.TransitionToNextState(state, context, result);
        }

    }
}
